<?php

namespace App\Traits;

use Illuminate\Support\Facades\Validator;

trait ValidatorTrait
{
    /**
     * 场景名称
     * @var null
     */
    protected $scene = null;

    /**
     * @var array 参数
     */
    protected $params = [];
    /**
     * @var array 校验的参数
     */
    protected $validateParams = [];
    /**
     * @var array 验证的规则
     */
    protected $validateRules = [];
    /**
     * @var \Illuminate\Support\MessageBag 错误信息
     */
    protected $errors = null;

    /**
     * @var static 单例模式
     */
    protected static $instance;

    public static function getInstance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /**
     * 默认错误消息
     * @var array
     */
    protected $defaultMassage = [
        "required" => ":attribute 不能为空",
        "required_if" => ":attribute 不能为空",
        "required_unless" => ":attribute 不能为空",
        "required_with" => ":attribute 不能为空",
        "between" => [
            'string' => ":attribute 长度必须在 :min 和 :max 之间",
            'numeric' => ":attribute 必须在 :min 和 :max 之间",
        ],
        "email" => ":attribute 格式错误",
        "regex" => ":attribute 格式错误",
        "mobile" => ":attribute 格式错误",
        'date_format' => ':attribute 与给定的格式 :format 不符合',
        'unique' => ':attribute 已存在',
        'min' => ':attribute 最小长度为 :min 位',
        'max' => ':attribute 最大长度为 :max 字符',
        'in' => ':attribute 不在操作范围',
        "numeric" => ":attribute 不为数字",
        "integer" => ":attribute 不为整数",
        "string" => ":attribute 不为字符串",
        "date" => ":attribute 格式错误",
        "after" => ":attribute 大于 :date",
        "gt" => ":attribute 需大于 :value",
        "exists" => ":attribute 数据不存在",
        "point" => ":attribute 只能保留小数点后 :num 位",
        "digits" => ":attribute 长度为 :digits 位",
        "digits_between" => ":attribute 长度为 :min 和 :max 之间",
        "present" => ":attribute 必须有",
    ];

    public function getParams(): array
    {
        return $this->params;
    }

    protected function setParams(array $params)
    {
        $this->params = $params;
        return $this;
    }

    public function getScene()
    {
        return $this->scene;
    }

    protected function setScene($scene)
    {
        $this->scene = $scene;
        return $this;
    }

    public function getErrors()
    {
        return $this->errors;
    }

    protected function setErrors($errors): void
    {
        $this->errors = $errors;
    }

    public function getValidateParams($except = [])
    {
        if ($except) {
            return array_diff_key($this->validateParams, array_flip($except));
        }
        return $this->validateParams;
    }

    protected function setValidateParams()
    {
        $this->validateParams = array_intersect_key($this->getParams(), $this->getValidateRules());
    }

    /**
     * 验证
     * @param array $params 需要验证的参数
     * @param string $scene 场景名称或验证规则
     */
    public function validate($params, $scene = '')
    {
        $this->setParams($params);
        $this->setScene($scene);
        $this->setValidateRules();
        $this->setValidateParams();

        // 验证的参数
        return $this->validateExec();
    }

    /**
     * @return bool
     */
    protected function validateExec()
    {
        $validator = Validator::make(
            $this->getParams(),
            $this->getValidateRules(),
            method_exists($this, 'message') ? $this->message() + $this->defaultMassage : $this->defaultMassage,
            method_exists($this, 'attributes') ? $this->attributes() : []
        );
        if ($validator->fails()) {
            $this->setErrors($validator->errors());
            return false;
        }

        return true;
    }

    /**
     * 返回所有错误
     * @return array
     * @author Chris Yu <chrisyu@crabapple.top> 2023/11/13
     */
    public function getErrorAll()
    {
        return $this->getErrors()->all();
    }

    /**
     * 返回首个错误
     * @param $validator
     * @return mixed
     */
    public function getErrorFirst()
    {
        return $this->getErrors()->first();
    }

    /**
     * 获取验证的 rules
     * @return array
     */
    protected function getValidateRules(): array
    {
        return $this->validateRules;
    }

    /**
     * 设置验证的 rules
     */
    protected function setValidateRules()
    {
        $scene = $this->getScene();
        $sceneRules = $this->sceneRules();
        $this->validateRules = $scene ? ($sceneRules[$scene] ?? []) : ($sceneRules['default'] ?? []);
    }
}